﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Drawing.Text;

namespace PickGold.Base
{
	/// <summary>
	/// 验证码
	/// Completely Automated Public Turing test to Tell Computers and Humans Apart
	/// </summary>
	[Serializable]
	public class CaptchaImage
	{
		private const int HEIGHT = 32;
		private const int FONT_SIZE = 16;
		private const int CODE_COUNT = 4;
		private const int FRAME_COUNT = 1;
		private const string CODE_FONT = "Arial";////Fixedsys//Georgia
		/// <summary>
		/// 0123456789ABCDEFGHIJKLMNOPQRSTUWXYZabcdefghijklmnopqrstuwxyz!@#$%&amp;?()[]{}&lt;&gt;=+
		/// </summary>
		public const string CODE_ORIGIN_A = "0123456789ABCDEFGHIJKLMNOPQRSTUWXYZabcdefghijklmnopqrstuwxyz!@#$%&?()[]{}<>=+";
		/// <summary>
		/// ABCDEFGHIJKLMNOPQRSTUWXYZabcdefghijklmnopqrstuwxyz
		/// </summary>
		public const string CODE_ORIGIN_B = "ABCDEFGHIJKLMNOPQRSTUWXYZabcdefghijklmnopqrstuwxyz";
		/// <summary>
		/// 0123456789ABCDEFGHIJKLMNOPQRSTUWXYZabcdefghijklmnopqrstuwxyz
		/// </summary>
		public const string CODE_ORIGIN_C = "0123456789ABCDEFGHIJKLMNOPQRSTUWXYZabcdefghijklmnopqrstuwxyz";
		/// <summary>
		/// 0123456789
		/// </summary>
		public const string CODE_ORIGIN_D = "0123456789";
		/// <summary>
		/// 0123456789ABCDEFGHIJKLMNOPQRSTUWXYZ
		/// </summary>
		public const string CODE_ORIGIN_E = "0123456789ABCDEFGHIJKLMNOPQRSTUWXYZ";

		/// <summary>
		/// ctor
		/// </summary>
		public CaptchaImage()
		{
			this._Random = new Random();
			this.Rotate = 60;
			this.Disturb = true;
			this.CodeCount = CODE_COUNT;
			this.CodeOrigin = CODE_ORIGIN_C;
			this.FrameCount = FRAME_COUNT;
			this.CodeFont = CODE_FONT;
			this.FontSize = FONT_SIZE;
			this.Height = HEIGHT;
			this.Rotate = 60;
		}
		/// <summary>
		/// 创建随机对象
		/// </summary>
		private Random _Random = null;
		/// <summary>
		/// 设置最少4位验证码
		/// </summary>
		public int CodeCount { set; get; }
		/// <summary>
		/// 
		/// </summary>
		private int FrameCount { set; get; }
		/// <summary>
		/// 
		/// </summary>
		public virtual string Code { set; get; }
		/// <summary>
		/// 
		/// </summary>
		public string CodeOrigin { set; get; }
		/// <summary>
		/// 是否消除锯齿
		/// </summary>
		public bool CodeRenderingHint { set; get; }
		/// <summary>
		/// 验证码字体
		/// </summary>
		public string CodeFont { set; get; }
		/// <summary>
		/// 验证码型号(像素)
		/// </summary>
		public int FontSize { set; get; }
		/// <summary>
		/// 
		/// </summary>
		public int Height { set; get; }
		/// <summary>
		/// 
		/// </summary>
		public int Width { set; get; }
		/// <summary>
		/// 旋转
		/// </summary>
		public int Rotate { set; get; }
		/// <summary>
		/// 背景色
		/// </summary>
		public Color BackColor { set; get; }
		/// <summary>
		/// 前景色
		/// </summary>
		public Color ForeColor { set; get; }
		/// <summary>
		/// 干扰
		/// </summary>
		public bool Disturb { set; get; }

		/// <summary>
		/// 获得随机验证码
		/// </summary>
		/// <returns></returns>
		public string CreateCode()
		{
			if (string.IsNullOrEmpty(this.CodeOrigin))
				this.CodeOrigin = CODE_ORIGIN_C;
			if (this.CodeCount <= 0)
				this.CodeCount = CODE_COUNT;
			var code = this.Code;
			if (code == null)
				code = string.Empty;
			//根据验证码的位数循环
			for (var i = code.Length; i < this.CodeCount; i++)
				code += this.CodeOrigin[this._Random.Next(this.CodeOrigin.Length - 1)];
			//错误检测,去除超过指定位数的验证码
			if (code.Length > this.CodeCount)
				code = code.Remove(this.CodeCount);
			return code;
		}
		/// <summary>
		/// 生成一帧的BMP图象
		/// </summary>
		/// <returns></returns>
		public Bitmap CreateImage()
		{
			var code = this.Code;
			if (string.IsNullOrEmpty(code))
			{
				code = this.CreateCode();
				this.Code = code;
			}
			if (this.CodeCount <= 0)
				this.CodeCount = CODE_COUNT;
			if (this.FontSize <= 0)
				this.FontSize = FONT_SIZE;
			if (this.Height <= 0)
				this.Height = HEIGHT;
			//图像的宽度-与验证码的长度成一定比例
			var w = this.Width;
			if (w <= 0)
				w = (int)(this.CodeCount * this.FontSize * 1.3 + 4);
			if (this.FrameCount <= 0)
				this.FrameCount = FRAME_COUNT;
			var imgs = new Bitmap[1];
			var brs = new int[this.FrameCount];
			var bgs = new int[this.FrameCount];
			var bbs = new int[this.FrameCount];
			var gs = new Graphics[this.FrameCount];
			for (var i = 0; i < this.FrameCount; i++)
			{
				imgs[i] = new Bitmap(w, this.Height);
				gs[i] = Graphics.FromImage(imgs[i]);
				if (this.BackColor == Color.Empty)
				{
					brs[i] = this._Random.Next(byte.MaxValue);
					bgs[i] = this._Random.Next(byte.MaxValue);
					bbs[i] = this._Random.Next(byte.MaxValue);
					//创建一个新绘图对象
					//清除背景色，并填充背景色
					gs[i].Clear(Color.FromArgb(sbyte.MaxValue, brs[i], bgs[i], bbs[i]));//Note:Color.Transparent为透明
					continue;
				}

				brs[i] = this.BackColor.R; ;
				bgs[i] = this.BackColor.G;
				bbs[i] = this.BackColor.B;
				//创建一个新绘图对象
				//清除背景色，并填充背景色
				gs[i].Clear(this.BackColor);//Note:Color.Transparent为透明
			}
			if (this.Disturb)//随机画线
			{
				for (var i = 0; i < 15; i++)
				{
					//创建随机点
					var lt = new Point(this._Random.Next(w), this._Random.Next(this.Height));
					var rb = new Point(this._Random.Next(w), this._Random.Next(this.Height));
					for (var ii = 0; ii < this.FrameCount; ii++)
					{
						if (this.ForeColor != Color.Empty)
						{
							gs[ii].DrawLine(new Pen(this.ForeColor, 1), lt, rb);
							continue;
						}

						var cr = (this._Random.Next(sbyte.MaxValue) + brs[ii] + sbyte.MaxValue / 2) % byte.MaxValue;
						var cg = (this._Random.Next(sbyte.MaxValue) + bgs[ii] + sbyte.MaxValue / 2) % byte.MaxValue;
						var cb = (this._Random.Next(sbyte.MaxValue) + bbs[ii] + sbyte.MaxValue / 2) % byte.MaxValue;
						gs[ii].DrawLine(new Pen(Color.FromArgb(sbyte.MaxValue + sbyte.MaxValue / 2, cr, cg, cb), 1), lt, rb);
					}
				}
			}
			if (string.IsNullOrEmpty(this.CodeFont))
				this.CodeFont = CODE_FONT;
			//绘图用的字体和字号
			var f = new Font(this.CodeFont, this.FontSize, FontStyle.Bold);
			//字体高度计算
			var fontHeight = (int)Math.Max(this.Height - this.FontSize - 3, 2);
			//开始随机安排字符的位置，并画到图像里
			for (int i = 0; i < code.Length; i++)
			{
				//生成随机点，决定字符串的开始输出范围
				var x = (w - 4) / this.CodeCount;
				x = i * x + this._Random.Next(x / 3) + 3;
				var y = this._Random.Next(fontHeight);
				var m = new Matrix();
				if (this.Rotate > 0)
					m.RotateAt(this._Random.Next(this.Rotate) - this.Rotate / 2, new PointF(x + y, y + y), MatrixOrder.Append);
				for (var ii = 0; ii < this.FrameCount; ii++)
				{
					//绘图用的刷子大小
					var cr = (this._Random.Next(sbyte.MaxValue) + brs[ii] + sbyte.MaxValue / 2) % byte.MaxValue;
					var cg = (this._Random.Next(sbyte.MaxValue) + bgs[ii] + sbyte.MaxValue / 2) % byte.MaxValue;
					var cb = (this._Random.Next(sbyte.MaxValue) + bbs[ii] + sbyte.MaxValue / 2) % byte.MaxValue;
					//var sb = new SolidBrush(cs[rand.Next(cs.Length - 1)]);
					var sb = new SolidBrush(Color.FromArgb(byte.MaxValue, cr, cg, cb));
					//消除锯齿操作
					if (this.CodeRenderingHint)
						gs[ii].TextRenderingHint = TextRenderingHint.SingleBitPerPixel;
					else
						gs[ii].TextRenderingHint = TextRenderingHint.AntiAlias;
					if (this.Rotate > 0)
					{
						gs[ii].ResetTransform();
						gs[ii].Transform = m;
					}
					//格式化刷子属性-用指定的刷子、颜色等在指定的范围内画图
					gs[ii].DrawString(code[i].ToString(), f, sb, x, y);
					//gs[ii].DrawString(CodeCharArray[i].ToString(), f, sb, 0, 0);
				}
			}
			for (var i = 0; i < this.FrameCount; i++)
				gs[i].Dispose();
			return imgs[0];
		}

		private ImageCodecInfo GetImageCodecInfo(string type)
		{
			var icis = ImageCodecInfo.GetImageEncoders();
			foreach (var ici in icis)
			{
				if (ici.FilenameExtension.IndexOf(type, StringComparison.OrdinalIgnoreCase) >= 0)
					return ici;
			}

			return null;
		}
	}
}
